
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include "list.h"
#include "cutils.h"
#include "quickjs.h"
//OBJECT_READ_WRITE

//JS_TAG_BIG_INT
//JSBigInt
//JS_LIMB_BITS
//mp_sub


/* binary object writer & reader */

//#pragma region MySection

//#pragma endregion



int malloc_count;
int malloc_size;

#define MALLOC_OVERHEAD  8

/* default memory allocation functions with memory limitation */
static size_t js_def_malloc_usable_size(const void *ptr)
{
    return malloc_usable_size((void *)ptr);
}

static void *js_def_malloc(JSMallocState *s, size_t size)
{
    void *ptr;

    /* Do not allocate zero bytes: behavior is platform dependent */
    //assert(size != 0);

    if (s->malloc_size + size > s->malloc_limit)
        return NULL;

    ptr = malloc(size);
    if (!ptr)
        return NULL;

    s->malloc_count++;
    s->malloc_size += js_def_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
    
    malloc_count = s->malloc_count;
    malloc_size = s->malloc_size;
    return ptr;
}

static void js_def_free(JSMallocState *s, void *ptr)
{
    if (!ptr)
        return;

    s->malloc_count--;
    s->malloc_size -= js_def_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
    free(ptr);
    malloc_count = s->malloc_count;
    malloc_size = s->malloc_size;
}

static void *js_def_realloc(JSMallocState *s, void *ptr, size_t size)
{
    size_t old_size;

    if (!ptr) {
        if (size == 0)
            return NULL;
        return js_def_malloc(s, size);
    }
    old_size = js_def_malloc_usable_size(ptr);
    if (size == 0) {
        s->malloc_count--;
        s->malloc_size -= old_size + MALLOC_OVERHEAD;
        free(ptr);
        return NULL;
    }
    if (s->malloc_size + size - old_size > s->malloc_limit)
        return NULL;

    ptr = realloc(ptr, size);
    if (!ptr)
        return NULL;

    s->malloc_size += js_def_malloc_usable_size(ptr) - old_size;
    
    malloc_count = s->malloc_count;
    malloc_size = s->malloc_size;

    return ptr;
}





static const JSMallocFunctions def_malloc_funcs = {
    js_def_malloc,
    js_def_free,
    js_def_realloc,
    js_def_malloc_usable_size,
};














// 打印 JS 错误
static void dump_exception(JSContext *ctx, JSValue v) {
    const char *str = JS_ToCString(ctx, v);
    if (str) {
        printf("Exception: %s\n", str);
        JS_FreeCString(ctx, str);
    } else {
        printf("Exception (unknown)\n");
    }
}

static JSValue js_print(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
    for (int i = 0; i < argc; i++) {
        const char *str = JS_ToCString(ctx, argv[i]);
        if (str) {
            printf("%s", str);
            JS_FreeCString(ctx, str);
        }
        if (i < argc - 1)
            printf(" ");
    }
    printf("\n");
    return JS_UNDEFINED;
}

int main(int argc, char **argv) {
    malloc_count = 0;
    malloc_size = 0;
    // 创建运行时和上下文
    JSRuntime *rt = JS_NewRuntime(&def_malloc_funcs, NULL);
    if (!rt) {
        fprintf(stderr, "Failed to create JSRuntime\n");
        exit(1);
    }
    printf("malloc_count: %d, %d\n", malloc_count, malloc_size);
    JSContext *ctx = JS_NewContext(rt);
    if (!ctx) {
        fprintf(stderr, "Failed to create JSContext\n");
        JS_FreeRuntime(rt);
        exit(1);
    }
    printf("malloc_count: %d, %d\n", malloc_count, malloc_size);

    JSValue global_obj = JS_GetGlobalObject(ctx);
    JS_SetPropertyStr(
        ctx,
        global_obj,
        "print",
        JS_NewCFunction(ctx, js_print, "print", 1)  // 参数 1 = 最少参数个数
    );
    JS_FreeValue(ctx, global_obj);
    printf("malloc_count: %d, %d\n", malloc_count, malloc_size);

    // 一段 JS 脚本
    const char *script = 
        "try{"
        "fdsa();"
        "}catch(ex){"
        "print(ex);"
        "}"
        "var r = Math.random();"
        "print(r);"
        "var a = 1.5;"
        "var b = Math.round(a);"
        "print(b);"
        "let obj = JSON.parse(`{\"aa\":123.123}`);"
        "print(obj.aa);"
        "let aa = parseFloat(`123.123`);"
        "print(aa);"
        "const add = (a, b)=>{ return a + b + 1.2; };"
        "let result = add(3.12321, 4.2);"
        "print(`true:8.523210`);"
        "print(result);"
        "var temp1 = 1.21;"
        "var temp2 = 3.421;"
        "var temp = temp1 / temp2;"
        "print(`true:0.3536977491961415`);"
        "print(temp);"
        "result;";

    // 执行脚本
    JSValue val = JS_Eval(ctx, script, strlen(script), "<input>", JS_EVAL_TYPE_GLOBAL);
    printf("malloc_count: %d, %d\n", malloc_count, malloc_size);

    if (JS_IsException(val)) {
        dump_exception(ctx, JS_GetException(ctx));
    } else {
        float int_result;
        if (JS_ToFloat64(ctx, &int_result, val) == 0) {
            printf("Result from JS: %f\n", int_result);
        }

        int int_result2;
        if (JS_ToInt32(ctx, &int_result2, val) == 0) {
            printf("Result2 from JS: %d\n", int_result2);
        }
        
    }
    printf("malloc_count: %d, %d\n", malloc_count, malloc_size);

    JS_FreeValue(ctx, val);
    JS_FreeContext(ctx);
    printf("malloc_count: %d, %d\n", malloc_count, malloc_size);

    JS_FreeRuntime(rt);
    return 0;
}